#ifndef _UTILS_H_
#define _UTILS_H_

/*
*	@file openPlantODBC.h
*	Header file for openPlant ODBC driver.
*
*	$Id:	openPlantODBC.h,v3.0 2009/03/03 10:19
*	Copyright (c) coanor <coanor1126@hotmail.com>
*/

#include "odbc_defines.h"

#if defined(_WIN32) || defined(_WIN64)
/*#include "resource.h"   @Note:need to define this file */
#define ODBC_INI "ODBC.INI"
#ifndef DRIVER_VER_INFO
#define DRIVER_VER_INFO VERSION
#endif
#else
#ifdef __OS2__
#define ODBC_INI "ODBC.INI"
#else
#define ODBC_INI ".odbc.ini"
#endif
#endif

#ifdef WIN32
#define SQL_API	 __stdcall
#else
#define SQL_API
#endif

#ifdef WITHOUT_WINTERFACE
#define WINTERFACE
#endif

#ifndef HAVE_SQLLEN
#define SQLLEN SQLINTEGER
#endif

#define SQLLEN_PTR SQLLEN *

#ifndef HAVE_SQLULEN
#define SQLULEN SQLUINTEGER
#endif

#ifndef HAVE_SQLSETPOSIROW
#define SQLSETPOSIROW SQLUSMALLINT
#endif

#ifndef HAVE_SQLROWOFFSET
#define SQLROWOFFSET SQLLEN
#endif

#ifndef HAVE_SQLROWSETSIZE
#define SQLROWSETSIZE SQLLEN
#endif

#ifndef FRIVER_VER_INFO
#define FRIVER_VER_INFO	"0.0"
#endif

#define min_(a, b) ((a) < (b) ? (a) : (b))
#define max_(a, b) ((a) < (b) ? (b) : (a))

#ifndef PTRDIFF_T
#define PTRDIFF_T int
#endif

#define array_size(x) (sizeof(x) / sizeof(x[0]))

#define stringify1(s) #s
#define stringify(s) stringify1(s)

#define ver_info(_maj_, _min_, _lev_) ((_maj_) << 16 | (_min_) << 8 | (_lev_))

/*
* isdigit() replacement w/o ctype.h
*/

static const char digit_chars[] = "0123456789";
#define ISDIGIT(c) \
	((c) && strchr(digit_chars, (c)) != NULL)

/*
* PointerIsValid
*		True if pointer is valid.
*/
#define PointerIsValid(pointer) ((void*)(pointer) != NULL)

/* Column types for static string column descriptions (SQLTables etc.) */ 
#if defined(WINTERFACE) && !defined(_WIN32) && !defined(_WIN64)
#define SCOL_VARCHAR SQL_WVARCHAR
#define SCOL_CHAR SQL_WCHAR
#else
#define SCOL_VARCHAR SQL_VARCHAR
#define SCOL_CHAR SQL_CHAR
#endif

#define OPENPLANT_VERSION "3.0"

static const char *xdigits = "0123456789ABCDEFabcdef";

#define MAX_CHAR_LENGTH 128


#if defined(_WIN32) || defined(_WIN64)
#define vsnprintf _vsnprintf
#define snprintf _snprintf
#define strcasecmp _stricmp
#define strncasecmp _strnicmp


/*
Most of the installer API functions in iODBC incorrectly reset the
config mode, so we need to save and restore it whenever we call those
functions. These macros reduce the clutter a little bit.
*/
#if USE_IODBC
# define SAVE_MODE() UWORD config_mode; (void)SQLGetConfigMode(&config_mode)
# define RESTORE_MODE() (void)SQLSetConfigMode(config_mode)
#else
# define SAVE_MODE()
# define RESTORE_MODE()
#endif

/*
* Many openPlant functions return an integer result code from 
* the set shown here in order to indicates success or failure.
*
* New error codes may be added in future versions of openPlant.
*/
#define OP_OK 0	/* Successful result */

/* beginning-of-error-codes */

#define OP_ERROR 1 /* SQL error or missing database */
#define OP_INTERNAL 2 /* Internal logic error in openPlant	 */
#define OP_PERM 3 /* Access permission denied */
#define OP_ABORT 4 /* Callback routine requested an abort */
#define OP_BUSY 5 /* The database file is locked */
#define OP_LOCKED 6 /* A table in the database is locked*/
#define OP_NOMEM 7 /* A malloc() failed */
#define OP_READONLY 8 /* Attempt to write a readonly database */
#define OP_INTERRUPT 9 /* Operation terminated by openPlant3_interrupt()	 */
#define OP_IOERR 10 /* Some kind of disk I/O error occurred */
#define OP_CORRUPT 11 /* The database disk image is malformed */
#define OP_NOTFOUND 12 /* NOT USED. Table or record not found  */
#define OP_FULL 13 /* Insertion failed because database is full	 */
#define OP_CANTOPEN 14 /* Unable to open the database file	 */
#define OP_PROTOCOL 15 /* NOT USED. Database lock protocol error */
#define OP_EMPTY 16 /* Database is empty	 */
#define OP_SCHEMA 17 /* The database schema changed	  */
#define OP_TOOBIG 18 /* String or BLOB exceeds size limit */
#define OP_CONSTRAINT 19 /* Abort due to constraint violation	  */
#define OP_MISMATCH 20 /* Data type mismatch */
#define OP_MISUSE 21 /* Library used incorrectly  */
#define OP_NOLFS 22 /* Uses OS features not supported on host	  */
#define OP_AUTH	23 /* Authorization denied */
#define OP_FORMAT 24 /* Auxiliary database format error  */
#define OP_RANGE 25 /* 2nd parameter to openPlant_bind out of range	 */
#define OP_NOTADB 26 /* File opened that is not a database file  */
#define OP_ROW 100 /* openPlant3_step() has another row ready  */
#define OP_DONE 101 /* openPlant3_step() has finished executing  */
/* end-of-error-codes */														 

#endif

#define ENV_MAGIC	0x53544145
#define DBC_MAGIC	0x53544144
#define DEAD_MAGIC 0xdeadbeef

typedef struct {
	char *name;				/* DSN name, such as "openPlant ODBC 3.0" */
	char *driver; 			/* driver filename */
	char *description;		/*  */
	char *server;			/* server IP address */
	char *uid;				/* User ID */
	char *pwd;				/* User password */
	char *database;			/* Database Name */
	char *initstmt;
	unsigned int port;			/*System port, openPlant default as 8200*/
	unsigned int timeout;		/* allowable second delay when connecting*/
} data_src_t;

#if defined(_WIN32) || defined(_WIN64)
SQLRETURN HDBC_LOCK(SQLHDBC hdbc);
void HDBC_UNLOCK(SQLHDBC hdbc);
SQLRETURN HSTMT_LOCK(SQLHSTMT hstmt);
void HSTMT_UNLOCK(SQLHSTMT hstmt);
#endif

data_src_t *ds_new();

void ds_delete(data_src_t *ds);

int ds_set_strattr(SQLCHAR **attr, const char *val);

int ds_set_strnattr(char **attr, const char *val, size_t charcount);

int ds_lookup(data_src_t *ds);

SQLPOINTER  strmak(char *dst, const char* src, int max, SQLSMALLINT *lenp);

char * uc_strncpy(char *dest, char *src, int len);

SQLRETURN no_memory(stmt_t *s);

SQLRETURN free_params(stmt_t *s);

char * uc_from_utf(unsigned char *str, int len);

void db_freemem(char * errp);

int uc_strlen(char *str);

char * strdup_(const char * str);

void uc_from_utf_buf(unsigned char *str, char *uc, int ucLen);

char * uc_to_utf(char *str, int len);

char * uc_to_utf_c(char *str, int len);

int map_default_type(int type, int stype, int nosign, int no_wchar);

int get_bool(char *string);

double ln_strtod(const char *data, char **endp);

void freep(void *x);

void s3stmt_end_if(stmt_t *s);

int str2timestamp(char *str, TIMESTAMP_STRUCT *tss);

int str2time(char *str, TIME_STRUCT *ts);

int str2date(char *str, DATE_STRUCT *ds);

void free_result(stmt_t *s, int clrcols);

void stmt_end_if(stmt_t *s);

void set_stat_dbc(dbc_t *d, int native_error, char *msg, char *st, ...);

void set_stat_stmt(stmt_t *s, int native_error, char *msg, char *st, ...);

int get_month_days(int year, int month);

void get_field_des(const char* field_name, int* type, int* len);

SQLRETURN free_stmt(SQLHSTMT stmt);

#endif